Skip to content

代码审计 BEESCMS

字数
1034 字
阅读时间
5 分钟
更新日期
7/15/2017

0x01 前言

跟着@Joseph 大牛学习代码审计系列(J牛审计文章见:https://forum.90sec.org/forum.php?mod=viewthread&tid=10630)

author:小草

BEESCMS企业网站管理系统拥有简单方便的模板标签,能够快速做出模板;自定义表单,自定义模型,内置新闻、下载、产品、招聘、单页模型;SEO功 能,每个页面都可以单独SEO优化;多语言,多风格,每种语言每个页面都可以定义风格;html静态页面生成功能;BEES还可以自定义flash引导页。

审计的是最新版本:v4

0x02 大牛的步伐

@Joseph 大牛审计漏洞出现在了 /member/member.php 文件上,

js
if($action=='ajajx_out'){
        $sql="update ".DB_PRE."member set member_time='{$_SESSION['m_time']}',member_ip='{$_SESSION['m_ip']}' where id={$_SESSION['member_id']}";

这段代码中由于 $_SESSION['m_ip'] 的值没有过滤,由get_ip()函数获取,而get_ip()函数值可以通过 x-forwarded-for来伪造造成了注入

但是漏洞过程比较繁琐,因为出现在了会员系统上,所以还需要注册一个新用户才能触发漏洞

0x03 跟随大牛的步伐

目的:J牛的利用方法有点复杂,想找个简单点的利用方法 因为beescms系统有着全局防注入,所有get post cookies请求都会被转换,所以需要找到一个未被转换的点。 全局搜索了下get_ip()出现的地方,在mx_form\order_save.php文件出现了 这是一个订单提交处理文件,说明可以之间在前台进行利用

360截图20170713202845921.jpg

但是这个一开始就被验证码挡住了,虽然验证码没什么大问题,但想着如果能写个批量化脚本验证的话,绕过验证码岂不是要好点。虽然弄个验证码的识别很容易。

然后看了下源码,在init.php中

js
@extract($_POST);
@extract($_GET);
@extract($_COOKIE);

这不就是变量覆盖漏洞吗?

所以可以这样提交来绕过验证码

js
POST http://127.0.0.1/beescms/mx_form/order_save.php
DATA feed_code=a&_SESSION=a

还是到后面这里就不知道怎么绕过了

360截图20170713203229569.jpg

js
if(!empty($fields)){
foreach($fields as $key=>$value){
                        if(!is_array($value)){
                        if(!in_array($key,$fd)){die("223333");}
                        }
                        $sql_field.=','.$key;
                        if(is_array($value)){
                                foreach($value as $k=>$v){
                                        $value_str.=$v.',';
                                }
                                $value=$value_str;
                        }
                        $sql_value.=",'".fl_html($value)."'";                        
}
}else{
        die($language['order_msg2']);
}

可以伪造fieldsfields变量的值是个数组呢? 。。

进行到这一步戛然而止 = -

然后找了下资料,发现曾经的dedecms变量覆盖漏洞有类似的利用方法,根据它的经验

修改如下的post data

js
feed_code=a&_SESSION[code]=a&form_id=5&fields[aaa][nnn]=1111

360截图20170714165147400.jpg

成功造成了注入

0x04 后台任意登陆

既然存在变量覆盖漏洞,那么就有很多可以利用的点

在这款CMS后台中,是如何检测登陆的呢?

js
//检查登陆
if(!is_login()){header('location:login.php');exit;}

is_login() 原型方法

js
function is_login(){
	if($_SESSION['login_in']==1&&$_SESSION['admin']){
		if(time()-$_SESSION['login_time']>3600){
			login_out();
		}else{
			$_SESSION['login_time']=time();
			@session_regenerate_id();
		}
		return 1;
	}else{
		$_SESSION['admin']='';
		$_SESSION['admin_purview']='';
		$_SESSION['admin_id']='';
		$_SESSION['admin_time']='';
		$_SESSION['login_in']='';
		$_SESSION['login_time']='';
		$_SESSION['admin_ip']='';
		return 0;
	}

}

由于前面的变量覆盖漏洞,$_session可以伪造,is_login()只要判断成功,后面再无判断

0x05 后台sql注入

出现在了后台 /admin/login.php 文件中,因为没有加载init.php这个文件(init.php包含了全局防注入代码)

js
//判断登录
elseif($action=='ck_login'){
	global $submit,$user,$password,$_sys,$code;
	$submit=$_POST['submit'];
	$user=fl_html(fl_value($_POST['user']));
	$password=fl_html(fl_value($_POST['password']));
	$code=$_POST['code'];
	if(!isset($submit)){
		msg('请从登陆页面进入');
	}
	if(empty($user)||empty($password)){
		msg("密码或用户名不能为空");
	}
	if(!empty($_sys['safe_open'])){
		foreach($_sys['safe_open'] as $k=>$v){
		if($v=='3'){
			if($code!=$s_code){msg("验证码不正确!");}
		}
		}
		}
	check_login($user,$password);
	
}

所以这个文件注入就很简单了,

js
function fl_value($str){
	if(empty($str)){return;}
	return preg_replace('/select|insert | update | and | in | on | left | joins | delete |\%|\=|\/\*|\*|\.\.\/|\.\/| union | from | where | group | into |load_file
|outfile/i','',$str);
}
define('INC_BEES','B'.'EE'.'SCMS');
function fl_html($str){
	return htmlspecialchars($str);
}

fl_html是html过滤,对sql影响不大

fl_value的原型是替换掉那些关键词,但是可以构造如 anandd 等等之类的绕过

撰写